package com.zzg.test2.manager

import android.content.Context
import android.webkit.WebResourceResponse
import com.leadbank.baselbf.log.LogBus
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.ByteArrayInputStream
import java.io.File
import java.net.URLEncoder
import java.util.Collections

/**
 *
 * @ClassName: WebViewCacheManager
 * @Description:
 * @Author: zhouzhiguo
 * @Date: 2025/8/27 10:34
 * @Version: 5.3.8
 */

class WebViewCacheManager(context: Context) {
    val TAG = "WebViewCacheManager"
    private val appContext = context.applicationContext
    private val cacheDir by lazy { File(appContext.cacheDir, "webview_cache") }
    private val maxCacheSize = 100 * 1024 * 1024 // 50MB
    private val cache = Collections.synchronizedMap(mutableMapOf<String, CacheEntry>())
    private val ioScope = CoroutineScope(Dispatchers.IO)

    init {
        if (!cacheDir.exists()) cacheDir.mkdirs()
        loadCacheIndex()
        monitorMemoryUsage()
    }

    // 获取缓存的资源
    fun getCachedResource(url: String): WebResourceResponse? {
        // 只缓存JS、CSS和图片等静态资源
        if (!shouldCache(url)) return null

        val cacheEntry = cache[url]
        return if (cacheEntry != null && cacheEntry.isValid()) {
            LogBus.d(TAG, "有缓存显示: $url")
            createWebResourceResponse(cacheEntry)
        } else {
            LogBus.d(TAG, "无缓存下载: $url")
            ioScope.launch {
                fetchAndCacheResource(url)
            }
            null // 返回null让WebView正常加载资源
        }
    }

    // 判断是否应该缓存该资源
    private fun shouldCache(url: String): Boolean {
        // 只缓存特定类型的资源
        return url.endsWith(".js") ||
                url.endsWith(".css") ||
                url.endsWith(".png") ||
                url.endsWith(".jpg") ||
                url.endsWith(".jpeg") ||
                url.endsWith(".gif") ||
                url.endsWith(".webp")
    }
    // 添加获取默认 MIME 类型的函数
    private fun getDefaultMimeType(url: String): String {
        return when {
            url.endsWith(".js", ignoreCase = true) -> "application/javascript"
            url.endsWith(".css", ignoreCase = true) -> "text/css"
            url.endsWith(".png", ignoreCase = true) -> "image/png"
            url.endsWith(".jpg", ignoreCase = true) || url.endsWith(".jpeg", ignoreCase = true) -> "image/jpeg"
            url.endsWith(".gif", ignoreCase = true) -> "image/gif"
            url.endsWith(".webp", ignoreCase = true) -> "image/webp"
            else -> "application/octet-stream"
        }
    }
    // 获取并缓存资源
    private suspend fun fetchAndCacheResource(url: String) {
        withContext(Dispatchers.IO) {
            try {
                val connection = java.net.URL(url).openConnection() as java.net.HttpURLConnection
                connection.connectTimeout = 10000
                connection.readTimeout = 10000

                if (connection.responseCode == 200) {
                    val contentType = connection.contentType ?: ""
                    val mimeType = if (contentType.isNotEmpty()) {
                        contentType.split(";").firstOrNull()?.trim() ?: getDefaultMimeType(url)
                    } else {
                        getDefaultMimeType(url)
                    }
//                    val mimeType = connection.contentType?.split(";")?.get(0) ?: "text/plain"
                    val encoding = connection.contentEncoding ?: "utf-8"
                    val inputStream = connection.inputStream
                    val data = inputStream.readBytes()
                    inputStream.close()

                    // 只缓存小于1MB的文件
                    if (data.size < 1024 * 1024) {
                        val cacheEntry = CacheEntry(
                            data = data,
                            mimeType = mimeType, // 确保这里不会为空
                            encoding = encoding,
                            timestamp = System.currentTimeMillis(),
                            ttl = if (url.endsWith(".js")) 24 * 60 * 60 * 1000 // JS文件缓存24小时
                            else 6 * 60 * 60 * 1000 // 其他资源缓存6小时
                        )

                        cache[url] = cacheEntry
                        saveToDisk(url, cacheEntry)
                    }
                }
                connection.disconnect()
            } catch (e: Exception) {
                // 处理异常
            }
        }
    }

    // 创建WebResourceResponse
    private fun createWebResourceResponse(entry: CacheEntry): WebResourceResponse {
        // 确保 MIME 类型不为空
        val mimeType = if (entry.mimeType.isNotEmpty()) {
            entry.mimeType
        } else {
            "application/octet-stream"
        }
        return WebResourceResponse(
            mimeType,
            entry.encoding,
            ByteArrayInputStream(entry.data)
        )
    }

    // 可选：改进索引文件格式以保存 MIME 类型
    private fun saveToDisk(url: String, entry: CacheEntry) {
        try {
            val file = File(cacheDir, URLEncoder.encode(url, "utf-8"))
            file.writeBytes(entry.data)

            // 更新索引（添加 MIME 类型）
            val indexFile = File(cacheDir, "index")
            indexFile.appendText("${file.name}|${url}|${entry.timestamp}|${entry.ttl}|${entry.mimeType}\n")
        } catch (e: Exception) {
            // 处理异常
            LogBus.d(TAG,e.printStackTrace())
        }
    }

    // 对应地修改 loadCacheIndex 来读取保存的 MIME 类型
    private fun loadCacheIndex() {
        try {
            val indexFile = File(cacheDir, "index")
            if (indexFile.exists()) {
                indexFile.readLines().forEach { line ->
                    val parts = line.split("|")
                    if (parts.size >= 5) { // 现在需要至少5个部分
                        val filename = parts[0]
                        val url = parts[1]
                        val timestamp = parts[2].toLong()
                        val ttl = parts[3].toLong()
                        val mimeType = parts[4] // 从索引中读取 MIME 类型

                        val file = File(cacheDir, filename)
                        if (file.exists()) {
                            val data = file.readBytes()
                            val encoding = "utf-8"
                            cache[url] = CacheEntry(data, mimeType, encoding, timestamp, ttl)
                        }
                    }
                }
            }
        } catch (e: Exception) {
            // 处理异常
            LogBus.d(TAG,e.printStackTrace())
        }
    }

    // 清理过期缓存
    suspend fun cleanupOldCache() {
        withContext(Dispatchers.IO) {
            val currentTime = System.currentTimeMillis()
            val iterator = cache.iterator()

            while (iterator.hasNext()) {
                val (url, entry) = iterator.next()
                if (!entry.isValid(currentTime)) {
                    iterator.remove()
                    // 从磁盘删除
                    val file = File(cacheDir, URLEncoder.encode(url, "utf-8"))
                    if (file.exists()) file.delete()
                }
            }

            // 如果缓存仍然太大，删除最旧的文件
            if (getCacheSize() > maxCacheSize) {
                val files = cacheDir.listFiles()?.filter { it.name != "index" } ?: emptyList()
                files.sortedBy { it.lastModified() }
                    .take((files.size * 0.2).toInt()) // 删除20%最旧的文件
                    .forEach { it.delete() }

                // 重建索引
                rebuildIndex()
            }
        }
    }

    // 获取缓存大小
    private fun getCacheSize(): Long {
        return cacheDir.listFiles()?.sumOf { it.length() } ?: 0
    }

    // 重建索引
    private fun rebuildIndex() {
        try {
            val indexFile = File(cacheDir, "index")
            indexFile.delete()

            cache.forEach { (url, entry) ->
                val filename = URLEncoder.encode(url, "utf-8")
                indexFile.appendText("$filename|$url|${entry.timestamp}|${entry.ttl}\n")
            }
        } catch (e: Exception) {
            // 处理异常
        }
    }

    // 监控内存使用
    private fun monitorMemoryUsage() {
        ioScope.launch {
            while (true) {
                delay(30000) // 每30秒检查一次

                // 如果内存使用过高，清理部分缓存
                val runtime = Runtime.getRuntime()
                val usedMemory = runtime.totalMemory() - runtime.freeMemory()
                val maxMemory = runtime.maxMemory()

                if (usedMemory > maxMemory * 0.7) {
                    // 内存使用超过70%，清理30%的缓存
                    val entriesToRemove = cache.entries.sortedBy { it.value.timestamp }
                        .take((cache.size * 0.3).toInt())

                    entriesToRemove.forEach { (url, _) ->
                        cache.remove(url)
                        val file = File(cacheDir, URLEncoder.encode(url, "utf-8"))
                        if (file.exists()) file.delete()
                    }

                    rebuildIndex()
                }
            }
        }
    }

    // 清理所有缓存
    fun cleanup() {
        ioScope.cancel()
        cache.clear()
        cacheDir.listFiles()?.forEach { it.delete() }
        cacheDir.delete()
    }

    // 缓存条目数据类
    data class CacheEntry(
        val data: ByteArray,
        val mimeType: String,
        val encoding: String,
        val timestamp: Long,
        val ttl: Long // 存活时间(毫秒)
    ) {
        fun isValid(currentTime: Long = System.currentTimeMillis()): Boolean {
            return currentTime - timestamp < ttl
        }

        override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (javaClass != other?.javaClass) return false

            other as CacheEntry

            if (!data.contentEquals(other.data)) return false
            if (mimeType != other.mimeType) return false
            if (encoding != other.encoding) return false
            if (timestamp != other.timestamp) return false
            if (ttl != other.ttl) return false

            return true
        }

        override fun hashCode(): Int {
            var result = data.contentHashCode()
            result = 31 * result + mimeType.hashCode()
            result = 31 * result + encoding.hashCode()
            result = 31 * result + timestamp.hashCode()
            result = 31 * result + ttl.hashCode()
            return result
        }
    }

}